import axios from 'axios'
import { ConfigurationOptions, ProviderConfiguration } from './configuration'
import { BigNumber } from '@ethersproject/bignumber'

import {
  DIDDocument,
  DIDResolutionOptions,
  DIDResolutionResult,
  DIDResolver,
  ParsedDID,
  Resolvable,
  ServiceEndpoint,
  VerificationMethod,
} from 'did-resolver'
import {
  interpretIdentifier,
  DIDAttributeChanged,
  DIDDelegateChanged,
  ERC1056Event,
  eventNames,
  legacyAlgoMap,
  legacyAttrTypes,
  LegacyVerificationMethod,
  verificationMethodTypes,
  identifierMatcher,
  nullAddress,
  DIDOwnerChanged,
  knownNetworks,
  Errors,
} from './helpers'
import { logDecoder } from './logParser'
import * as qs from 'querystring'
import { computeAddress } from '@ethersproject/transactions'

interface Authentication {
  type: string
  publicKey: string
}

interface Proof {
  type: string
  creator: string
  signatureValue: string
}

interface UdpnDidDocument {
  did: string
  version: number
  created: string
  updated: string
  authentication: Authentication
  recovery: Authentication
  proof: Proof
}

export function getResolver(options: ConfigurationOptions): Record<string, DIDResolver> {
  return new UdpnDidResolver(<ProviderConfiguration>options).build()
}

export class UdpnDidResolver {
  private rpcUrl: string | undefined

  constructor(options: ProviderConfiguration) {
    this.rpcUrl = options.rpcUrl
  }

  async getUdpnDidDocument(identity: string): Promise<UdpnDidDocument> {
    let didDocument!: UdpnDidDocument
    await axios
      .post<UdpnDidDocument>(`${this.rpcUrl}/did/getDidDocument`, { did: identity })
      .then(function (response: any) {
        if (response.data && response.data.code === 200) {
          didDocument = response.data.data
        }
      })
      .catch(function (error: any) {
        console.log(error)
      })
    return didDocument
  }

  wrapDidDocument(did: string): {
    didDocument: DIDDocument
    deactivated: boolean
    versionId: number
    nextVersionId: number
  } {
    const baseDIDDocument: DIDDocument = {
      '@context': [
        'https://www.w3.org/ns/did/v1',
        'https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld',
      ],
      id: did,
      verificationMethod: [],
      authentication: [],
      assertionMethod: [],
    }

    const authentication = [`${did}#controller`]

    // const versionId = udpnDidDocument.version
    const versionId = 0
    const nextVersionId = Number.POSITIVE_INFINITY
    const deactivated = false

    const publicKeys: VerificationMethod[] = [
      {
        id: `${did}#controllerKey`,
        type: verificationMethodTypes.EcdsaSecp256k1RecoveryMethod2020,
        controller: did,
      },
    ]

    /*if (udpnDidDocument.authentication) {
      // 04 + publicKey
      const publicKey = BigNumber.from(udpnDidDocument.authentication.publicKey).toHexString().replace('0x', '0x04')
      publicKeys.push({
        id: `${did}#controllerKey`,
        type: verificationMethodTypes.EcdsaSecp256k1RecoveryMethod2020,
        controller: did,
        publicKeyHex: computeAddress(publicKey),
      })
      authentication.push(`${did}#controllerKey`)
    }*/

    const didDocument: DIDDocument = {
      ...baseDIDDocument,
      verificationMethod: publicKeys,
      authentication: authentication,
    }
    didDocument.assertionMethod = [...(didDocument.verificationMethod?.map((pk) => pk.id) || [])]

    return deactivated
      ? {
          didDocument: { ...baseDIDDocument, '@context': 'https://www.w3.org/ns/did/v1' },
          deactivated,
          versionId,
          nextVersionId,
        }
      : { didDocument, deactivated, versionId, nextVersionId }
  }

  async resolve(
    did: string,
    parsed: ParsedDID,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    _unused: Resolvable,
    options: DIDResolutionOptions
  ): Promise<DIDResolutionResult> {
    const fullId = parsed.id.match(identifierMatcher)
    if (!fullId) {
      return {
        didResolutionMetadata: {
          error: Errors.invalidDid,
          message: `Not a valid did:ethr: ${parsed.id}`,
        },
        didDocumentMetadata: {},
        didDocument: null,
      }
    }

    //const udpnDidDocument: UdpnDidDocument = await this.getUdpnDidDocument(did)

    try {
      const { didDocument, deactivated, versionId, nextVersionId } = this.wrapDidDocument(did)
      const status = deactivated ? { deactivated: true } : {}
      let versionMeta = {}
      let versionMetaNext = {}
      if (versionId !== 0) {
        versionMeta = {
          versionId: 0,
          updated: 0,
        }
      }
      if (nextVersionId !== Number.POSITIVE_INFINITY) {
        versionMetaNext = {
          nextVersionId: 0,
          nextUpdate: 0,
        }
      }
      return {
        didDocumentMetadata: { ...status, ...versionMeta, ...versionMetaNext },
        didResolutionMetadata: { contentType: 'application/did+ld+json' },
        didDocument,
      }
    } catch (e) {
      return {
        didResolutionMetadata: {
          error: Errors.notFound,
          message: e.toString(), // This is not in spec, nut may be helpful
        },
        didDocumentMetadata: {},
        didDocument: null,
      }
    }
  }

  build(): Record<string, DIDResolver> {
    return { cbt: this.resolve.bind(this) }
  }
}
